/**
  ************************************* Copyright ******************************
  * FileName   : oled242.c
  * Version    : v1.0
  * Author     : yychao
  * Date       : 2023-11-15
  * Description:
  * Function List:
  	1. ....
  	   <version>:
  <modify staff>:
  		  <data>:
   <description>:
  	2. ...
  ******************************************************************************
 */
#include "n32l40x_gpio.h"
#include "oled242.h"
#include "stdlib.h"
#include "oledfont.h"
#include "systick.h"
#include "log.h"

#define LEN (128)
#define PAGE (8)
uint8_t OLED_GRAM[LEN][PAGE];

void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{
    uint8_t i;
    if(cmd)
        OLED_DC_Set();
    else
        OLED_DC_Clr();
    OLED_CS_Clr();
    for(i=0; i<8; i++)
    {
        OLED_SCL_Clr();
        if(dat&0x80)
            OLED_SDA_Set();
        else
            OLED_SDA_Clr();
        OLED_SCL_Set();
        dat<<=1;
    }
    OLED_CS_Set();
    OLED_DC_Set();
}


void OLED_ColorTurn(uint8_t i)
{
    if(i==0) {
        OLED_WR_Byte(0xA6,OLED_CMD);
    } else if(i==1) {
        OLED_WR_Byte(0xA7,OLED_CMD);
    }
}

void OLED_DisplayTurn(uint8_t i)
{
    if(i==0) {
        OLED_WR_Byte(0xC8,OLED_CMD);
        OLED_WR_Byte(0xA1,OLED_CMD);
    } else if(i==1) {
        OLED_WR_Byte(0xC0,OLED_CMD);
        OLED_WR_Byte(0xA0,OLED_CMD);
    }
}

void OLED_DisPlay_On(void)
{
    OLED_WR_Byte(0x8D,OLED_CMD);//
    OLED_WR_Byte(0x14,OLED_CMD);//
    OLED_WR_Byte(0xAF,OLED_CMD);//
}

void OLED_DisPlay_Off(void)
{
    OLED_WR_Byte(0x8D,OLED_CMD);//
    OLED_WR_Byte(0x10,OLED_CMD);//
    OLED_WR_Byte(0xAE,OLED_CMD);//
}


void OLED_Refresh(void)
{
    uint8_t i,n;
    for(i=0; i<PAGE; i++)
    {
        OLED_WR_Byte(0xb0+i,OLED_CMD); //
        OLED_WR_Byte(0x00,OLED_CMD);   //
        OLED_WR_Byte(0x10,OLED_CMD);   //
        for(n=0; n<LEN; n++)
            OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
    }
}

void OLED_Clear(uint8_t color)
{
    if(color == 0) {
        color = 0;
    } else {
        color = 0xff;
    }
    uint8_t i,n;
    for(i=0; i<PAGE; i++)
    {
        for(n=0; n<LEN; n++)
        {
            OLED_GRAM[n][i]=color;//
        }
    }
    OLED_Refresh();//
}

void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t)
{
    uint8_t i,m,n;
    i=y/8;
    m=y%8;
    n=1<<m;
    if(t) {
        OLED_GRAM[x][i]|=n;
    }
    else {
        OLED_GRAM[x][i]=~OLED_GRAM[x][i];
        OLED_GRAM[x][i]|=n;
        OLED_GRAM[x][i]=~OLED_GRAM[x][i];
    }
}

void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode)
{
    uint16_t t;
    int xerr=0,yerr=0,delta_x,delta_y,distance;
    int incx,incy,uRow,uCol;
    delta_x=x2-x1; //
    delta_y=y2-y1;
    uRow=x1;//
    uCol=y1;
    if(delta_x>0)incx=1; //
    else if (delta_x==0)incx=0;//
    else {
        incx=-1;
        delta_x=-delta_x;
    }
    if(delta_y>0)incy=1;
    else if (delta_y==0)incy=0;//
    else {
        incy=-1;
        delta_y=-delta_x;
    }
    if(delta_x>delta_y)distance=delta_x; //
    else distance=delta_y;
    for(t=0; t<distance+1; t++)
    {
        OLED_DrawPoint(uRow,uCol,mode);//
        xerr+=delta_x;
        yerr+=delta_y;
        if(xerr>distance)
        {
            xerr-=distance;
            uRow+=incx;
        }
        if(yerr>distance)
        {
            yerr-=distance;
            uCol+=incy;
        }
    }
}

void OLED_DrawCircle(uint8_t x,uint8_t y,uint8_t r)
{
    int a, b,num;
    a = 0;
    b = r;
    while(2 * b * b >= r * r)
    {
        OLED_DrawPoint(x + a, y - b,1);
        OLED_DrawPoint(x - a, y - b,1);
        OLED_DrawPoint(x - a, y + b,1);
        OLED_DrawPoint(x + a, y + b,1);

        OLED_DrawPoint(x + b, y + a,1);
        OLED_DrawPoint(x + b, y - a,1);
        OLED_DrawPoint(x - b, y - a,1);
        OLED_DrawPoint(x - b, y + a,1);

        a++;
        num = (a * a + b * b) - r*r;//
        if(num > 0)
        {
            b--;
            a--;
        }
    }
}



void OLED_Init(void)
{

    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);

    GPIO_InitType GPIO_InitStructure;
    GPIO_InitStructure.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Pull = GPIO_Pull_Up;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = GPIO_PIN_13|GPIO_PIN_15;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
//	GPIO_InitStructure.GPIO_Pull = GPIO_Pull_Up;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    OLED_RES_Clr();
    SysTick_Delay_Ms(200);
    OLED_RES_Set();
    OLED_WR_Byte(0xFD,OLED_CMD);
    OLED_WR_Byte(0x12,OLED_CMD);
    OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
    OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
    OLED_WR_Byte(0xA0,OLED_CMD);
    OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
    OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WR_Byte(0x00,OLED_CMD);//-not offset
    OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping
    OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction
    OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration
    OLED_WR_Byte(0x12,OLED_CMD);
    OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control register
    OLED_WR_Byte(0x7F,OLED_CMD);// Set SEG Output Current Brightness
    OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period
    OLED_WR_Byte(0x82,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
    OLED_WR_Byte(0x34,OLED_CMD);//Set VCOM Deselect Level
    OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
    OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
    OLED_Clear(0x00);
    OLED_WR_Byte(0xAF,OLED_CMD);
}
/*****************************************************************************
 * @name       :void LCD_ShowChar(u16 x,u16 y,u16 fc, u16 bc, u8 num,u8 size,u8 mode)
 * @date       :2018-08-09
 * @function   :Display a single English character
 * @parameters :x:the bebinning x coordinate of the Character display position
                y:the bebinning y coordinate of the Character display position
								fc:the color value of display character
								bc:the background color of display character
								num:the ascii code of display character(0~94)
								size:the size of display character
								mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/
void OLED_ShowChar(u16 x,u16 y, u8 num,u8 size,u8 mode)
{
    u8 temp;
    u8 pos,t;
    uint8_t disp1 = 0;
    uint8_t disp2 = 0;

    num=num-' ';//得到偏移后的值
    if (mode != 0) {
        disp1 = 0;
        disp2 = 1;
    } else {
        disp1 = 1;
        disp2 = 0;
    }
    for (pos = 0; pos < size; pos++) {
        if (size == 12)
            temp = asc2_1206[num][pos];		 //调用1206字体
        else
            temp = asc2_1608[num][pos];		 //调用1608字体
        for (t = 0; t < size / 2; t++) {
            if (temp & 0x01)
                OLED_DrawPoint(x + t, y + pos, disp1);		 //画一个点
            else
                OLED_DrawPoint(x + t, y + pos, disp2);
            temp >>= 1;
        }
    }


}
/*****************************************************************************
 * @name       :void GUI_DrawFont16(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
 * @date       :2018-08-09
 * @function   :Display a single 16x16 Chinese character
 * @parameters :x:the bebinning x coordinate of the Chinese character
                y:the bebinning y coordinate of the Chinese character
								fc:the color value of Chinese character
								bc:the background color of Chinese character
								s:the start address of the Chinese character
								mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/
void OLED_DrawFont16(u16 x, u16 y, u8 *s,u8 mode)
{
    u8 i,j;
    u16 k;
    u16 HZnum;
    u16 x0=x;
    uint8_t disp1 = 0;
    uint8_t disp2 = 0;
    if (mode != 0) {
        disp1 = 0;
        disp2 = 1;
    } else {
        disp1 = 1;
        disp2 = 0;
    }

    HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);	//自动统计汉字数目

    for (k=0; k<HZnum; k++)
    {
        if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
        {
            for(i=0; i<16*2; i++)
            {
                for(j=0; j<8; j++)
                {

                    if(tfont16[k].Msk[i]&(0x80>>j))
                        OLED_DrawPoint(x, y, disp1);
                    else
                        OLED_DrawPoint(x, y, disp2);
                    x++;
                    if((x-x0)==16)
                    {
                        x=x0;
                        y++;
                        break;
                    }

                }

            }

        }
        continue;
    }
}
/*****************************************************************************
 * @name       :void GUI_DrawFont24(u16 x, u16 y, u16 fc, u16 bc, u8 *s,u8 mode)
 * @date       :2018-08-09
 * @function   :Display a single 24x24 Chinese character
 * @parameters :x:the bebinning x coordinate of the Chinese character
                y:the bebinning y coordinate of the Chinese character
								fc:the color value of Chinese character
								bc:the background color of Chinese character
								s:the start address of the Chinese character
								mode:0-no overlying,1-overlying
 * @retvalue   :None
******************************************************************************/
void OLED_DrawFont24(u16 x, u16 y, u8 *s,u8 mode)
{
    u8 i,j;
    u16 k;
    u16 HZnum;
    u16 x0=x;

    uint8_t disp1 = 0;
    uint8_t disp2 = 0;
    if (mode != 0) {
        disp1 = 0;
        disp2 = 1;
    } else {
        disp1 = 1;
        disp2 = 0;
    }


    HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);	//自动统计汉字数目

    for (k=0; k<HZnum; k++)
    {
        if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
        {
            for(i=0; i<24*3; i++)
            {
                for(j=0; j<8; j++)
                {

                    if(tfont24[k].Msk[i]&(0x80>>j)) OLED_DrawPoint(x, y, disp1);
                    else  OLED_DrawPoint(x, y, disp2);
                    x++;
                    if((x-x0)==24)
                    {
                        x=x0;
                        y++;
                        break;
                    }

                }
            }


        }
        continue;  //查找到对应点阵字库立即退出，防止多个汉字重复取模带来影响
    }
}
void OLED_ShowStr(u16 x, u16 y, u8 *str,u8 size,u8 mode)
{
    u16 x0=x;
    u8 bHz=0;     //字符或者中文
    while(*str!=0)//数据未结束
    {
        if(!bHz)
        {
            if(x>(128-size/2)||y>(64-size))
                return;
            if(*str>0x80)bHz=1;//中文
            else              //字符
            {
                if(*str==0x0D)//换行符号
                {
                    y+=size;
                    x=x0;
                    str++;
                }
                else
                {
                    if(size>16)//字库中没有集成12X24 16X32的英文字体,用8X16代替
                    {
                        OLED_ShowChar(x,y,*str,16,mode);
                        x+=8; //字符,为全字的一半
                    }
                    else
                    {
                        OLED_ShowChar(x,y,*str,size,mode);
                        x+=size/2; //字符,为全字的一半
                    }
                }
                str++;

            }
        } else//中文
        {
            if(x>(128-size)||y>(64-size))
                return;
            bHz=0;//有汉字库
            if(size==24)
                OLED_DrawFont24(x,y,str,mode);
            else
                OLED_DrawFont16(x,y,str,mode);

            str+=2;
            x+=size;//下一个汉字偏移
        }
    }
}
void OLED_Pic(u16 x, u16 y, u8 *pic, u8 x_len, u8 mode) {
    //OLED_DrawPoint(100, 63,1);

    uint8_t tx = x;
    uint8_t ty = y;
    uint8_t pic_num = 0;

    for(uint8_t i = 0; i< x_len; i++) {
        x = x+8;
        for(uint8_t j = 0; j< 16; j++) {
            ty = y+j;
            pic_num = pic[i*16+j];
            for(uint8_t k = 0; k < 8; k++) {
                tx=x+k;
                if(mode == 0) {
                    OLED_DrawPoint(tx,ty,!getbit(pic_num,k));
                } else {
                    OLED_DrawPoint(tx,ty,getbit(pic_num,k));
                }

            }

        }
    }
}

